const toString = Object.prototype.toString

export class Check {
  /**
   * @description 判断是否是Object类型
   */
  static isObject(value) {
    return toString.call(value) === '[object Object]'
  }

  static isPlainObject(value) {
    return value && Check.isObject(value) && Reflect.ownKeys(value).length === 0
  }

  /**
   * @description 判断是否是String类型
   */
  static isString(value) {
    return toString.call(value) === '[object String]'
  }

  /**
   * @description 判断是否是Boolean类型
   */
  static isNumber(value) {
    return toString.call(value) === '[object Number]'
  }
}

/**
 *@desc 将json参数转换为url字符串，如果json只有一层，则直接拼接，超过一层则直接JSON.stringify转为字符串处理
 *
 */
const encodeUrl = (str, encode) => (encode === undefined || encode) ? encodeURIComponent(str) : str

export function jsonToUrlStr(param, encode) {
  if (param === null) return ''

  let paramStr = ''

  const keys = Object.keys(param)
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    const val = param[key]

    let valStr = ''
    if (typeof s === 'object') {
      valStr = JSON.stringify(val)
    }
    else {
      valStr = val
    }

    paramStr += `${i === 0 ? '' : '&'}${encodeUrl(key, encode)}=${encodeUrl(valStr, encode)}`
  }

  return paramStr
}

export function paramsToUrl(obj) {
  return Object.entries(obj)
    .map((item) => {
      const key = item[0]
      const val = item[1]

      switch (typeof val) {
        case 'number':
          return `${key}=${val}_nn`
        case 'string':
          return `${key}=${val}_ss`
        case 'boolean':
          return `${key}=${val}_bb`
        case 'undefined':
          return `${key}=undefined_uu`
        default:
          if (val === null) {
            return `${key}=null_ll`
          }
          else {
            try {
              return `${key}=${JSON.stringify(val)}_oo`
            }
            catch (error) {
              return `${key}=${val}_ss`
            }
          }
      }
    })
    .join('&')
}

export function paramsToObj(obj) {
  return Object.entries(obj).reduce((prev, cur) => {
    const key = cur[0]
    let val = cur[1]
    const type = val.slice(-3)
    if (!['_nn', '_ss', '_bb', '_uu', '_ll', '_oo'].includes(type)) {
      prev[key] = val
      return prev
    }
    val = val.slice(0, -3)

    let res
    switch (type) {
      case '_nn':
        res = Number(val)
        break
      case '_ss':
        res = val
        break
      case '_bb':
        res = val !== 'false'
        break
      case '_uu':
        res = undefined
        break
      case '_ll':
        res = null
        break
      case '_oo':
        try {
          res = JSON.parse(val)
        }
        catch (error) {
          res = {}
        }
        break
      default:
        res = val
    }
    prev[key] = res
    return prev
  }, {})
}

export function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj
  }

  if (obj instanceof Date) {
    return new Date(obj.getTime())
  }

  if (Array.isArray(obj)) {
    return obj.reduce((arr, item, i) => {
      arr[i] = deepClone(item)
      return arr
    }, [])
  }

  if (obj instanceof Object) {
    return Object.keys(obj).reduce((newObj, key) => {
      newObj[key] = deepClone(obj[key])
      return newObj
    }, {})
  }
}
